//
// Created by Administrator on 2020/9/17.
//

#ifndef P2PCLIENT_UDP_CLIENT_H
#define P2PCLIENT_UDP_CLIENT_H

#include <string>
#include <cstdint>
#include <map>
#include <set>
#include <iostream>
#include <random>
#include "asio.hpp"
#include "chat_message.h"
#include "peer.h"

class UdpClient {
public:

    const static int UDP_PORT_MIN = 1024;
    const static int UDP_PORT_MAX = 65535;

    static int get_random(int min, int max)
    {
        static std::default_random_engine e(time(nullptr));
        static std::uniform_int_distribution<int> u(min, max);

        return u(e);
    }

    UdpClient(const uint16_t& local_port, asio::io_context& io_context, PeerMgr &peer_mgr);
    UdpClient(const std::string& address, const std::string& port, PeerMgr &peer_mgr);
    UdpClient(const UdpClient&) = delete;
    UdpClient& operator=(const UdpClient&) = delete;
    UdpClient(const UdpClient&&) = delete;
    UdpClient& operator=(const UdpClient&&) = delete;

    void start();
    bool connect();
    int send_data(const char*, size_t);
    size_t read_data();

    int send_data(const char* send_buff, size_t length, const std::string& ip, const std::string& port);
    int send_data(const char* send_buff, size_t length, const std::string& ip, const uint16_t & port);
    int send_data(const char* send_buff, size_t length, PeerInfo &pi);
    int send_data(const char* send_buff, size_t length, PeerInfoPtr pi);
    
    void async_send_data(const char* send_buff, size_t length, const std::string& ip, const uint16_t & port);
    void async_send_data(const std::string& ip, const std::string& port);

    void do_receive();

    void refresh_port(int num);
    int punch(std::string str);


    uint16_t get_reflexive_port() const;

    std::string get_reflexive_ip() const;

private:
    asio::io_context io_context_;
    asio::ip::udp::resolver::results_type remote_endpoints_;
    asio::ip::udp::socket socket_;
    asio::ip::udp::endpoint recv_endpoint_;
    asio::ip::udp::resolver resolver_;
    int count_;
    //char data_[512];
    chat_message msg;
    uint16_t reflexive_port_;
    std::string reflexive_ip_;
    PeerMgr &peer_mgr_;

};

#endif //P2PCLIENT_UDP_CLIENT_H
